home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.11 Nov 95 / PowerAndRemainder.c < prev   
Encoding:
C/C++ Source or Header  |  1995-09-18  |  18.0 KB  |  514 lines  |  [TEXT/R*ch]

  1. /*
  2. I call my fixed length numbers "BigFixed" and translate from BigNum's
  3. to BigFixed's in the PowerAndRemainder routine. These are the assembly
  4. language routines which are the guts of my program:
  5.  
  6. (1) PowerMod -- raises a number to a power and reduces it by a modulus. It
  7. uses a fast binary exponentiation algorithm, reducing by the modulus at
  8. each step.
  9. (2) Multiply -- multiplies 2 BigNum's together.
  10. (3) MultQ -- mutliplies a BigNum by a long int.
  11. (4) Divide -- divides one BigNum by another and supplies the quotient and
  12. remainder.
  13. (5) Compare -- determines the ordering of 2 BigNum's.
  14.  
  15. Some of the loops have been expanded to make more efficient use of the instruction cache.
  16. */
  17.  
  18. #define NumSize 72
  19.  
  20. typedef struct BigNum
  21. {
  22.    short           numDig;
  23.    unsigned char   *dig;
  24. } BigNum;
  25.  
  26. typedef struct BigFixed
  27. {
  28.    unsigned char   dig[NumSize*4];
  29. } BigFixed;
  30.  
  31. /* We need 72 longs because the division routine needs
  32. the most significant longword to be zero and
  33. the speed optimization requires that NumSize be
  34. a multiple of four. */
  35.  
  36. void PowerAndRemainder(BigNum *msg, BigNum *exp, BigNum *n,
  37.    BigNum *res);
  38. void PowerMod(BigFixed *msg, BigFixed *exp, BigFixed *n,
  39.    BigFixed *res);
  40. void Multiply(BigFixed *src1, BigFixed *src2, BigFixed *dst);
  41. void MultQ(BigFixed *src1, long src2, BigFixed *dst);
  42. void Divide(BigFixed *end, BigFixed *sor, BigFixed *dst);
  43. short Compare(BigFixed *src1, BigFixed *src2);
  44.  
  45.  
  46. void PowerAndRemainder(BigNum *msg, BigNum *exp, BigNum *n,
  47.    BigNum *res)
  48. {
  49.    short      a, b, numDigits;
  50.    BigFixed   msg0, exp0, n0, res0;
  51.    
  52.    for (a = 0; a < NumSize*4; a++)
  53.    {
  54.       b = NumSize*4 - msg->numDig;
  55.       if (a < b) msg0.dig[a] = 0;
  56.       else msg0.dig[a] = msg->dig[a - b];
  57.       b = NumSize*4 - exp->numDig;
  58.       if (a < b) exp0.dig[a] = 0;
  59.       else exp0.dig[a] = exp->dig[a - b];
  60.       b = NumSize*4 - n->numDig;
  61.       if (a < b) n0.dig[a] = 0;
  62.       else n0.dig[a] = n->dig[a - b];
  63.    }
  64.    PowerMod(&msg0, &exp0, &n0, &res0);
  65.    a = 0;
  66.    while (res0.dig[a] == 0) a++;
  67.    numDigits = res->numDig = NumSize*4 - a;
  68.    for (b = 0; b < numDigits; b++)
  69.       res->dig[b] = res0.dig[a++];
  70. }
  71.  
  72. void PowerMod(BigFixed *msg, BigFixed *exp, BigFixed *n,
  73.    BigFixed *res)
  74. {
  75.    BigFixed   acc, scrap;
  76.  
  77.    asm
  78.    {
  79.    LEA      acc, A0            ;   Start with one in
  80.    MOVEQ    #NumSize/4-2, D0   ;   accumulator
  81. @Z CLR.L    (A0)+
  82.    CLR.L    (A0)+
  83.    CLR.L    (A0)+
  84.    CLR.L    (A0)+
  85.    DBF      D0, @Z
  86.    CLR.L    (A0)+
  87.    CLR.L    (A0)+
  88.    CLR.L    (A0)+
  89.    MOVEQ    #1, D0
  90.    MOVE.L   D0, (A0)
  91.    MOVEA.L  exp, A0            ;   Put address of
  92.                                ;   exponent in A0
  93.    CLR.W    D2                 ;   D2 holds position
  94.                                ;   in exponent
  95. @6 TST.L    00(A0, D2.W*4)     ;   Find first longword
  96.                                ;   of exponent
  97.    BNE      @4                 ;   which is not zero
  98.    CMPI.W   #NumSize-1, D2
  99.    BEQ      @5                 ;   If entire exponent
  100.                                ;   is zero, leave
  101.    ADDQ.W   #1, D2
  102.    BRA      @6
  103. @4 CLR.L    D1                 ;   D1 holds the bit #
  104. @2 PEA      acc                ;   Square accumulator
  105.    PEA      acc
  106.    PEA      acc
  107.    JSR      Multiply
  108.    ADDA.W   #12, A7
  109.    MOVE.L   n, -(A7)           ;   Compare accumulator
  110.    PEA      acc                ;   to modulus
  111.    JSR      Compare
  112.    ADDQ.W   #8, A7
  113.    TST.B    D0
  114.    BMI      @7                 ;   If it's less, skip
  115.                                ;   reduction
  116.    PEA      scrap              ;   Reduce accumulator
  117.                                ;   modulo "n"
  118.    MOVE.L   n, -(A7)           ;   Quotient not needed,
  119.    PEA      acc                ;   store in "scrap"
  120.    JSR      Divide
  121.    ADDA.W   #12, A7
  122. @7 BFTST    00(A0, D2.W*4){D1:1} ; Test a bit in current
  123.                                ;   longword of exponent
  124.    BEQ      @1                 ;   If zero, skip multiply
  125.    PEA      acc                ;   Multiply accumulator
  126.    PEA      acc                ;   by base
  127.    MOVE.L   msg, -(A7)
  128.    JSR      Multiply
  129.    ADDA.W   #12, A7
  130.    MOVE.L   n, -(A7)           ;   Compare accumulator
  131.    PEA      acc                ;   to modulus
  132.    JSR      Compare
  133.    ADDQ.W   #8, A7
  134.    TST.B    D0
  135.    BMI      @1                 ;   If it's less, skip
  136.                                ;   reduction
  137.    PEA      scrap              ;   Reduce modulo "n"
  138.    MOVE.L   n, -(A7)
  139.    PEA      acc
  140.    JSR      Divide
  141.    ADDA.W   #12, A7
  142. @1 ADDQ.W   #1, D1             ;   Increase bit number
  143.    CMPI.B   #32, D1
  144.    BLT      @2                 ;   If < 32, loop
  145.    ADDQ.W   #1, D2             ;   Increase longword #
  146.    CMPI.W   #NumSize, D2
  147.    BLT      @4                 ;   If < number size, loop
  148. @5 LEA      acc, A0            ;   Copy acc to "res"
  149.    MOVEA.L  res, A1
  150.    MOVEQ    #NumSize/4-1, D0
  151. @3 MOVE.L   (A0)+, (A1)+
  152.    MOVE.L   (A0)+, (A1)+
  153.    MOVE.L   (A0)+, (A1)+
  154.    MOVE.L   (A0)+, (A1)+
  155.    DBF      D0, @3
  156.    }
  157. }
  158.  
  159. /* Multiply src1 by src2 and put product in dst */
  160.  
  161. void Multiply(BigFixed *src1, BigFixed *src2, BigFixed *dst)
  162. {
  163.    short      topStop, botStop;
  164.    BigFixed   acc, line;
  165.    
  166.    asm
  167.    {
  168.    MOVEM.L  D0-D7/A0-A4, -(A7)
  169.    LEA      acc, A0            ;   Clear accumulator
  170.    MOVEQ    #NumSize/4-1, D0
  171. @Z CLR.L    (A0)+
  172.    CLR.L    (A0)+
  173.    CLR.L    (A0)+
  174.    CLR.L    (A0)+
  175.    DBF      D0, @Z
  176.    LEA      line, A2           ;   "line" holds partial
  177.                                ;   products
  178.    MOVEA.L  src1, A3           ;   Move bottom number's
  179.    CLR.W    D1                 ;   address into A3
  180. @6 TST.L    00(A3, D1.W*4)     ;   Find first non-zero
  181.    BNE      @7                 ;   longword of bottom #
  182.    ADDQ.W   #1, D1
  183.    CMPI.W   #NumSize, D1       ;   If bottom number 0,
  184.    BEQ      @8                 ;   go to end
  185.    BRA      @6                 ;   Loop
  186. @7 MOVE.W   D1, botStop
  187.    MOVEQ    #NumSize - 1, D4   ;   D4 holds position in
  188.                                ;   bottom number
  189. @4 MOVEA.L  src2, A4           ;   Move top number's
  190.    CLR.W    D1                 ;   address into A4
  191. @9 TST.L    00(A4, D1.W*4)     ;   Find first non-zero
  192.    BNE      @A                 ;   longword of top #
  193.    ADDQ.W   #1, D1
  194.    CMPI.W   #NumSize, D1       ;   If top number zero,
  195.    BEQ      @8                 ;   go to end
  196.    BRA      @9                 ;   Loop
  197. @A SUBQ.W   #1, D1
  198.    BPL      @X
  199.    CLR.W    D1
  200. @X MOVE.W   D1, topStop
  201. @B CLR.L    00(A2, D1.W*4)     ;   Clear leading longwords
  202.    DBF      D1, @B             ;   of partial product
  203.    ADDA.W   #NumSize * 4, A4   ;   Add size
  204.    CLR.L    D2                 ;   D2 is carry register
  205.    MOVE.L   00(A3, D4.W*4), D7 ;   Get longword from
  206.                                ;   bottom number
  207.    MOVEQ    #NumSize - 1, D3   ;   D3 holds position
  208.                                ;   in product
  209. @1 MOVE.L   D7, D5             ;   Copy longword to D5
  210.    MULU.L   -(A4), D6:D5       ;   Do 64-bit multiply
  211.    ADD.L    D2, D5             ;   Add carry to low
  212.                                ;   longword of product
  213.    CLR.L    D2                 ;   Use D2 as dummy to
  214.                                ;   extend carry
  215.    ADDX.L   D2, D6             ;   Add zero to high
  216.                                ;   longword with carry
  217.    MOVE.L   D6, D2             ;   Anything in high
  218.                                ;   longword gets carried
  219.    MOVE.L   D5, 00(A2, D3.W*4) ;   Store low longword in
  220.                                ;   partial product
  221.    SUBQ.W   #1, D3             ;   Loop through all
  222.    CMP.W    topStop, D3        ;   longwords in top number
  223.    BGE      @1
  224.    MOVEA.L  A2, A0             ;   Now add partial product
  225.                                ;   to accumulator
  226.    MOVE.L   D4, D0             ;   Calculate correct
  227.                                ;   position in product
  228.    LEA      acc, A1            ;   Get accumulator's addr
  229.    ADDQ.W   #1, D0
  230.    ADDA.W   #NumSize * 4, A0
  231.    LSL.W    #2, D0
  232.    ADDA.W   D0, A1
  233.    MOVE.W   D4, D1
  234.    MOVE.L   -(A1), D0          ;   Get longword of product
  235.    SUBQ     #1, D1
  236.    ADD.L    -(A0), D0          ;   Add longword of
  237.    MOVE.L   D0, (A1)           ;   partial product
  238.    TST.W    D1                 ;   If no more longwords,
  239.    BMI      @2                 ;   then branch
  240. @3 ADDX.L   -(A0), -(A1)       ;   Add next longword
  241.    DBF      D1, @3             ;   Loop through
  242.                                ;   entire product
  243. @2 SUBQ.W   #1, D4             ;   Loop and do next
  244.    CMP.W    botStop, D4        ;   longword of bottom #
  245.    BGE      @4
  246. @8 LEA      acc, A0            ;   Copy product to "dst"
  247.    MOVEA.L  dst, A1
  248.    MOVEQ    #NumSize/4-1, D0
  249. @5 MOVE.L   (A0)+, (A1)+
  250.    MOVE.L   (A0)+, (A1)+
  251.    MOVE.L   (A0)+, (A1)+
  252.    MOVE.L   (A0)+, (A1)+
  253.    DBF      D0, @5
  254.    MOVEM.L  (A7)+, D0-D7/A0-A4
  255.    }
  256. }
  257.  
  258. /* Multiply src1 by src2 and put product in dst */
  259.  
  260. void MultQ(BigFixed *src1, long src2, BigFixed *dst)
  261. {
  262.    BigFixed   pro;
  263.    
  264.    asm
  265.    {
  266.    MOVEM.L  D0-D7/A0/A1, -(A7)
  267.    LEA      pro, A0            ;   Clear product
  268.    MOVEQ    #NumSize/4-1, D0
  269. @Z CLR.L    (A0)+
  270.    CLR.L    (A0)+
  271.    CLR.L    (A0)+
  272.    CLR.L    (A0)+
  273.    DBF      D0, @Z
  274.    LEA      pro, A1            ;   Get address of
  275.                                ;   product
  276.    MOVEA.L  src1, A0           ;   Move top number's
  277.    CLR.W    D1                 ;   address into A0
  278. @3 TST.L    00(A0, D1.W*4)     ;   Find first non-zero
  279.    BNE      @4                 ;   longword of top #
  280.    ADDQ.W   #1, D1
  281.    CMPI.W   #NumSize, D1       ;   If top number zero,
  282.    BEQ      @5                 ;   go to end
  283.    BRA      @3                 ;   Loop
  284. @4 SUBQ.W   #1, D1
  285.    BPL      @X
  286.    CLR.W    D1
  287. @X MOVEQ    #NumSize - 1, D0   ;   D0 holds position
  288.                                ;   in top number
  289.    MOVE.L   src2, D7           ;   Bottom number
  290.                                ;   is one longword
  291.    CLR.L    D2                 ;   D2 is carry register
  292. @1 MOVE.L   00(A0, D0.W*4), D4 ;   Get longword of
  293.                                ;   top number
  294.    MULU.L   D7, D5:D4          ;   Do 64-bit multiply
  295.                                ;   by bottom number
  296.    ADD.L    D2, D4             ;   Add carry
  297.    CLR.L    D2                 ;   Use D2 as dummy to
  298.                                ;   extend carry
  299.    ADDX.L   D2, D5             ;   Add zero with carry
  300.    MOVE.L   D5, D2             ;   High longword
  301.                                ;   becomes carry
  302.    MOVE.L   D4, 00(A1, D0.W*4) ;   Put partial product
  303.                                ;   into result
  304.    SUBQ.W   #1, D0             ;   Loop through all
  305.    CMP.W    D1, D0             ;   longwords in top #
  306.    BGE      @1
  307. @5 LEA      pro, A0            ;   Copy product to "dst"
  308.    MOVEA.L  dst, A1
  309.    MOVEQ    #NumSize/4-1, D0
  310. @2 MOVE.L   (A0)+, (A1)+
  311.    MOVE.L   (A0)+, (A1)+
  312.    MOVE.L   (A0)+, (A1)+
  313.    MOVE.L   (A0)+, (A1)+
  314.    DBF      D0, @2
  315.    MOVEM.L  (A7)+, D0-D7/A0/A1
  316.    }
  317. }
  318.  
  319. /* Divide end (dividend) by sor (divisor) and put
  320.    quotient in dst. Remainder will end up in end */
  321.  
  322. void Divide(BigFixed *end, BigFixed *sor, BigFixed *dst)
  323. {
  324.    long      pq;
  325.    BigFixed  quo, line;
  326.    
  327.    asm
  328.    {
  329.    MOVEM.L  D0-D7/A0-A4, -(A7)
  330.    LEA      quo, A0            ;   Clear quotient
  331.    MOVEQ    #NumSize/4-1, D0
  332. @Z CLR.L    (A0)+
  333.    CLR.L    (A0)+
  334.    CLR.L    (A0)+
  335.    CLR.L    (A0)+
  336.    DBF      D0, @Z
  337.    MOVEA.L  end, A0            ;   Move dividend's
  338.                                ;   address into A0
  339.    CLR.W    D0                 ;   D0 contains current
  340.                                ;   position in dividend
  341.    MOVEA.L  sor, A1            ;   Move divisor's addr
  342.    CLR.W    D1                 ;   into A1
  343. @2 TST.L    00(A1, D1.W*4)     ;   This loop finds the
  344.                                ;   first non-zero
  345.    BNE      @G                 ;   longword of the divisor
  346.    ADDQ.W   #1, D1             ;   & stores the pos in D1
  347.    BRA      @2                 ;   Loop until something
  348.                                ;   is found
  349. @G TST.L    00(A0, D0.W*4)     ;   Find first longword
  350.    BNE      @1                 ;   of dividend
  351.    ADDQ.W   #1, D0
  352.    CMPI.W   #NumSize, D0       ;   If whole dividend zero,
  353.    BEQ      @H                 ;   go to end
  354.    BRA      @G                 ;   Loop
  355. @1 LEA      quo, A2            ;   Address of quotient
  356.                                ;   is stored in A2
  357.    MOVEQ    #NumSize, D2       ;   D2 contains current
  358.                                ;   position in quotient
  359.    SUB.W    D1, D2             ;   First position will
  360.    SUBQ.W   #1, D0             ;   be NumSize - D1
  361.    CMP.W    D0, D1             ;   If dividend smaller
  362.                                ;   than divisor,
  363.    BLE      @H                 ;   then go to end
  364.    ADD.W    D0, D2             ;   Add to quotient pos
  365. @C CLR.L    pq;                ;   "pq" holds partial
  366.                                ;   quotients
  367. @9 MOVE.L   00(A0, D0.W*4), D3 ;   Take a quadword from
  368.                                ;   dividend to use
  369.    MOVE.L   04(A0, D0.W*4), D4 ;   as partial dividend
  370.    MOVE.L   00(A1, D1.W*4), D5 ;   Take a longword from
  371.                                ;   divisor and
  372.    ADDQ.L   #1, D5             ;   add one
  373.    BNE      @E                 ;   If divisor not zero,
  374.                                ;   go do division
  375.    MOVE.L   D3, D4             ;   Else, we are dividing
  376.                                ;   by $10000, so move
  377.    BRA      @F                 ;   high longword of
  378.                                ;   dividend into quotient
  379. @E DIVU.L   D5, D3:D4          ;   Do 64-bit division
  380. @F BEQ      @D                 ;    Branch if quotient zero
  381.    ADD.L    D4, pq             ;   Add quotient to
  382.                                ;   partial quotient
  383.    PEA      line               ;   Multiply quotient
  384.                                ;   by divisor
  385.    MOVE.L   D4, -(A7)          ;   and store in "line"
  386.    MOVE.L   sor, -(A7)
  387.    JSR      MultQ
  388.    ADDA.W   #12, A7
  389.    LEA      line, A3           ;   Get quotient-divisor
  390.                                ;   product
  391.    ADDA.W   #NumSize * 4, A3   ;   Now subtract
  392.                                ;   from dividend
  393.    MOVEA.L  A0, A4             ;   Cpy dividend addr to A4
  394.    MOVE.L   D2, D5             ;   D2 holds lowest pos
  395.    LSL.W    #2, D5             ;   of dividend to sub from
  396.    ADDA.W   D5, A4             ;   Add it to partial
  397.    MOVEQ    #NumSize, D7       ;   dividend address
  398.    SUB.W    D1, D7             ;   D7 holds number of
  399.    SUBQ.W   #1, D7             ;   longwords to subtract
  400.    SMI      D5
  401.    MOVE.L   (A4), D6           ;   Subtract least
  402.    SUB.L    -(A3), D6          ;   significant longwords
  403.    MOVE.L   D6, (A4)
  404.    TST.B    D5                 ;   If there are not any
  405.                                ;   more longwords
  406.    BNE      @B                 ;   to subtract, branch
  407. @A SUBX.L   -(A3), -(A4)       ;   Subtract rest of
  408.    DBF      D7, @A             ;   longwords with borrow
  409. @B BRA      @9                 ;   Loop and divide again
  410. @D MOVE.L   pq, D4             ;   Get accumulated
  411.                                ;   partial quotient
  412. @8 MOVE.L   D0, D5             ;   Now check to see
  413.    ADDQ.L   #1, D5             ;   if partial dividend is
  414.    MOVE.L   D1, D6             ;   less than divisor
  415. @5 MOVE.L   00(A1, D6.W*4), D7 ;   Get longword of divisor
  416.    CMP.L    00(A0, D5.W*4), D7 ;   Compare with longword
  417.                                ;   of dividend, branch
  418.    BCS      @3                 ;   if dividend bigger
  419.    BNE      @4                 ;   If divisor bigger,
  420.                                ;   then branch
  421.    ADDQ.L   #1, D5             ;   If these two longwords
  422.    ADDQ.L   #1, D6             ;   were =, then compare
  423.    CMP.W    D2, D5             ;   next two longwords and
  424.    BLE      @5                 ;   continue
  425. @3 MOVEA.L  A1, A3             ;   Subtract divisor from
  426.    ADDA.W   #NumSize * 4, A3   ;   partial dividend
  427.    MOVEA.L   A0, A4
  428.    MOVE.L   D2, D5
  429.    LSL.W    #2, D5
  430.    MOVEQ    #NumSize, D7
  431.    ADDA.W   D5, A4
  432.    SUB.W    D1, D7
  433.    SUBQ.W   #2, D7
  434.    SMI      D5
  435.    MOVE.L   (A4), D6
  436.    SUB.L    -(A3), D6
  437.    MOVE.L   D6, (A4)
  438.    TST.B    D5
  439.    BNE      @6
  440. @7 SUBX.L   -(A3), -(A4)
  441.    DBF      D7, @7
  442. @6 ADDQ.L   #1, D4             ;   Add one to quotient
  443.    BRA      @8                 ;   Loop and compare again
  444. @4 MOVE.L   D4, 00(A2, D2.W*4) ;   Store partial quotient
  445.                                ;   in whole quotient
  446.    ADDQ.W   #1, D2             ;   Increase quotient pos
  447.    ADDQ.W   #1, D0             ;   Increase dividend pos
  448.    CMPI.W   #NumSize, D2
  449.    BLT      @C                 ;   Loop until done
  450. @H LEA      quo, A0            ;   Copy quotient to "dst"
  451.    MOVEA.L  dst, A1            ;   Remainder will automat-
  452.    MOVEQ    #NumSize/4-1, D0   ;   ically end up
  453. @0 MOVE.L   (A0)+, (A1)+       ;   in dividend
  454.    MOVE.L   (A0)+, (A1)+
  455.    MOVE.L   (A0)+, (A1)+
  456.    MOVE.L   (A0)+, (A1)+
  457.    DBF      D0, @0
  458.    MOVEM.L  (A7)+, D0-D7/A0-A4
  459.    }
  460. }
  461.  
  462. /* Compare src1 and src2. Returns 1 if src1 > src2,
  463.    0 if they're equal, and -1 if src1 < src2. */
  464.  
  465. short Compare(BigFixed *src1, BigFixed *src2)
  466. {
  467.    asm
  468.    {
  469.    MOVEM.L  D1/D2/A0/A1, -(A7)
  470.    MOVEA.L  src1, A0           ;   Get src1's address
  471.    MOVEA.L  src2, A1           ;   Get src2's address
  472.    MOVEQ    #1, D0             ;   Start with +1
  473.    MOVE.L   (A0)+, D2
  474.    CMP.L    (A1)+, D2          ;   Compare 1st longwords
  475.    BLT      @1                 ;   If src1 less, branch
  476.    BNE      @2                 ;   If !=, src1 must
  477.    MOVE.L   (A0)+, D2          ;   be greater
  478.    CMP.L    (A1)+, D2          ;   Cmp 3 more longwords
  479.    BCS      @1                 ;   (Unsigned)
  480.    BNE      @2
  481.    MOVE.L   (A0)+, D2
  482.    CMP.L    (A1)+, D2
  483.    BCS      @1
  484.    BNE      @2
  485.    MOVE.L   (A0)+, D2
  486.    CMP.L    (A1)+, D2
  487.    BCS      @1
  488.    BNE      @2
  489.    MOVEQ    #NumSize/4-2, D1   ;   Number of longwords
  490.                                ;   remaining / 4
  491. @3 MOVE.L   (A0)+, D2          ;   Compare 4 longwords
  492.    CMP.L    (A1)+, D2
  493.    BCS      @1
  494.    BNE      @2
  495.    MOVE.L   (A0)+, D2
  496.    CMP.L    (A1)+, D2
  497.    BCS      @1
  498.    BNE      @2
  499.    MOVE.L   (A0)+, D2
  500.    CMP.L    (A1)+, D2
  501.    BCS      @1
  502.    BNE      @2
  503.    MOVE.L   (A0)+, D2
  504.    CMP.L    (A1)+, D2
  505.    BCS      @1
  506.    BNE      @2
  507.    DBF      D1, @3             ;   Loop
  508.    CLR.L    D0                 ;   If we get here,
  509.    BRA      @2                 ;   then src1 = src2
  510. @1 MOVEQ    #-1, D0            ;   src1 is less
  511. @2 MOVEM.L  (A7)+, D1/D2/A0/A1
  512.    }
  513. }
  514.